/*******************************************************************************
GDialog.cpp

	Author:		LiuDingXi
	e-mail:		liudx@gmail.com
	Date time:	2009-08-07

	Copyright (C) 2009
	All rights reserved.
	
*******************************************************************************/
#include "StdAfx.h"
#include "GDialog.h"
#include "GControl.h"
#include "GSprite.h"
#include "GUtil.h"

#if (_OS_ == _OS_WINNT_)
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#endif//(_OS_ == _OS_WINNT_)

////////////////////////////////////////////////////////////////////////////////

GDialog::GDialog()
{
	m_ppItems = NULL;
	m_bModal = TRUE;
	m_pNext = NULL;
}

GDialog::~GDialog()
{
	Destroy();
}

BOOL GDialog::Create(GScene* pScene, UINT nID)
{
	if(pScene)
	{
		m_pScene = pScene;
		return m_pScene->InitDialog(this, nID);
	}
	return FALSE;
}

BOOL GDialog::Destroy()
{
	if(m_ppItems && m_pThis)
	{
		const DIALOG* pThis = (const DIALOG*)m_pThis;
		for(int i=0; i<pThis->nItem; i++)
		{
			if(m_ppItems[i].bDestroy)
			{
				delete m_ppItems[i].pControl;
			}
		}
		delete[] m_ppItems;
		m_ppItems = NULL;

		return TRUE;
	}
	return FALSE;
}

BOOL GDialog::DataBind(GSight* pSight, const BYTE* pBase, SceneDat::PTR ptr)
{
	m_pBase = pBase;
	m_pThis = (const DIALOG*)(pBase + ptr);

	const DIALOG* pThis = (const DIALOG*)m_pThis;
	if(pThis->nItem > 0 && m_ppItems == NULL)
	{
		m_ppItems = new PITEM[pThis->nItem];
		if(m_ppItems)
		{
			memset(m_ppItems, 0, sizeof(PITEM)*(pThis->nItem));
			return OnInitDialog(pSight);
		}
	}
	return FALSE;
}

BOOL GDialog::OnInitDialog(GSight* pSight)
{
	const DIALOG* pThis = (const DIALOG*)m_pThis;
	if(m_ppItems)
	{
		for(int i=0; i<pThis->nItem; i++)
		{
			if(m_ppItems[i].pControl == NULL)
			{
				SceneDat::PTR ptr = pThis->pItem[i].pItem;
				const CONTROL* pItem = (const CONTROL*)(m_pBase + ptr);

				m_ppItems[i].bDestroy = TRUE;
				m_ppItems[i].pControl = NewCtrl(pItem->nType);
				m_ppItems[i].pControl->DataBind(pSight, m_pBase, ptr);
			}
		}
	}
	return TRUE;
}

BOOL GDialog::InitItem(GSight* pSight, GControl* pCtrl, UINT nID, BOOL bDestroy)
{
	const DIALOG* pThis = (const DIALOG*)m_pThis;

	if(pThis && pThis->nItem > 0)
	{
		if(nID >= 0 && nID < pThis->nItem)
		{
			if(m_ppItems)
			{
				m_ppItems[nID].bDestroy = bDestroy;
				m_ppItems[nID].pControl = pCtrl;
			}
			return pCtrl->DataBind(pSight, m_pBase, pThis->pItem[nID].pItem);
		}
	}
	return FALSE;	
}

bool GDialog::IsVisible()const
{
	if(m_pThis)
	{
		return true;
	}
	return false;
}

BOOL GDialog::IsValid()const
{
	if(m_pThis && m_ppItems)
	{
		return true;
	}
	return false;
}

GControl* GDialog::GetItem(SINT i)const
{
	ASSERT(m_pThis);
	const DIALOG* pThis = (const DIALOG*)m_pThis;

	if(pThis && m_ppItems && i >= 0 && i < pThis->nItem)
	{
		GControl* pItem = m_ppItems[i].pControl;
		return pItem;
	}
	return NULL;
}

void GDialog::OnDraw(GDC* pDC)
{
	ASSERT(m_pThis);

	const DIALOG* pThis = (const DIALOG*)m_pThis;

	if(m_ppItems)
	{
		for(int i=0; i<pThis->nItem; i++)
		{
			GControl* pItem = m_ppItems[i].pControl;
			if(pItem && pItem->IsVisible())
			{
				int x = m_nPosX + pThis->pItem[i].nPosX;
				int y = m_nPosY + pThis->pItem[i].nPosY;
				pItem->SetPos(x, y);
				pItem->OnDraw(pDC);
			}
		}
	}
}

void GDialog::Update(UINT nMillisecond)
{
	ASSERT(m_pThis);

	const DIALOG* pThis = (const DIALOG*)m_pThis;

	if(m_ppItems)
	{
		for(int i=0; i<pThis->nItem; i++)
		{
			GControl* pItem = m_ppItems[i].pControl;
			if(pItem)
			{
				pItem->Update(nMillisecond);
			}
		}
	}
}

BOOL GDialog::GetBox(BOX& refBox)const
{
	const DIALOG* pThis = (const DIALOG*)m_pThis;

	if(m_ppItems)
	{
		int i = 0;
		for(; i<pThis->nItem; i++)
		{
			if(m_ppItems[i].pControl)
			{
				m_ppItems[i].pControl->GetBox(refBox);
				refBox.left += pThis->pItem[i].nPosX;
				refBox.right += pThis->pItem[i].nPosX;
				refBox.top += pThis->pItem[i].nPosY;
				refBox.bottom += pThis->pItem[i].nPosY;
				break;
			}
		}

		for(i=1; i<pThis->nItem; i++)
		{
			if(m_ppItems[i].pControl)
			{
				BOX box;
				m_ppItems[i].pControl->GetBox(box);
				box.left += pThis->pItem[i].nPosX;
				box.right += pThis->pItem[i].nPosX;
				box.top += pThis->pItem[i].nPosY;
				box.bottom += pThis->pItem[i].nPosY;
				Merge(refBox, box);
			}
		}

		refBox.left += m_nPosX;
		refBox.right += m_nPosX;
		refBox.top += m_nPosY;
		refBox.bottom += m_nPosY;

		return TRUE;
	}
	return FALSE;
}

BOOL GDialog::GetCxy(CXY& refCxy)const
{
	BOX box;
	if(GetBox(box))
	{
		refCxy.cx = box.right - box.left;
		refCxy.cy = box.bottom - box.top;
		return TRUE;
	}
	return FALSE;
}

void GDialog::EndDialog()
{
	if(m_pScene)
	{
		m_pScene->RemoveTail(this);
	}
}

BOOL GDialog::DoModal(int x, int y)
{
	if(m_pScene && m_pThis)
	{
		m_bModal = TRUE;
		SetPos(x, y);
		m_pScene->AddTail(this, GScene::eDialog);
		return TRUE;
	}
	return FALSE;
}

PMRV GDialog::ProcMsg(GMsg& refMsg)
{
	const DIALOG* pThis = (const DIALOG*)m_pThis;

	if(pThis && m_ppItems)
	{	
		int i = pThis->nItem - 1;
		for(; i>= 0; i--)
		{
			if(m_ppItems[i].pControl)
			{
				PMRV ret = m_ppItems[i].pControl->ProcMsg(refMsg);
				if(ret != PM_PASS)
				{
					if(OnCommand(i, refMsg.nNotify))
					{
						break;
					}
				}
			}
		}
		if(m_bModal)
		{
			return PM_HOLD;
		}
	}
	return PM_PASS;
}

BOOL GDialog::OnCommand(UINT nCtrlId, UINT nCommand)
{
	switch(nCommand)
	{
	case NTF_CLOSE:
		EndDialog();
		return TRUE;

	case NTF_CLICK_UP:
		{
			const DIALOG* pThis = (const DIALOG*)m_pThis;

			switch(pThis->pItem[nCtrlId].nNtfy)
			{
			case NTF_CLOSE:
			case NTF_CANCEL:
			case NTF_OK:
				EndDialog();
				return TRUE;
			}
		}
		break;
	}
	return FALSE;
}
